/**
 * @file 区域碰撞demo
 * todo: 1. 绘制自定义图形
 *       2. 自定义图形类型
 *       3. 测距
 *       4. 测面积
 *       5. 绘制的图形不能相交
 *       6. 当前缩放比例看不相交，但是放大后相交
 * 优化:
 *  1. 当数据量过大时使用集群展示,
 *  2. 使用热力图展示
 */
import 'bootstrap/dist/css/bootstrap.min.css';
import "assets/styles/common/index.less";
import "./assets/styles/index.less";
import { Tooltip } from 'bootstrap';
import $ from 'jquery';
import 'ol/ol.css';
import Map from 'ol/Map';
import View from 'ol/View';
import Feature from 'ol/Feature'
import Collection from 'ol/Collection'
import { unByKey } from 'ol/Observable'
import {Circle as CircleStyle, Fill, Icon, Stroke, Text, Style} from 'ol/style';
import Draw, { createBox } from 'ol/interaction/Draw';
import {Cluster, OSM, Vector as VectorSource} from 'ol/source';
import {Tile as TileLayer, Vector as VectorLayer} from 'ol/layer';
import { getProjectionRadius, getMeterRadius, formatLength } from './utils/help.js'
import Point from 'ol/geom/Point';
import locatePng from './assets/image/locate.png'
import locateSelectedPng from './assets/image/locateSelected.png'
import intersectionWith from 'lodash/intersectionWith'
import isEmpty from 'lodash/isEmpty'
import { Overlay } from 'ol';
import { getAllPoint, getIntersectionPoint } from './api/areaCollide.js'
import * as turf from '@turf/turf'
import GeoJSON from 'ol/format/GeoJSON';
import {result as resResult} from './data/resData.js'

/**
 * 绘制图形时检测区域碰撞
 * 思路:
 * 1. 当开始绘制时如果开始坐标再其他的矢量图形中则禁止绘制, 使用draw.abortDrawing()实现
 * 2. 绘制时根据turf.intersect是否相交, 如果相交则此圆的最大半径就获取到了
 * 3. 获取到最大半径后，如果当前圆的半径大于最大半径则将半径设置为最大半径
 * 滑块实现方式
 * 
 */

const main = {
  featureChangeListener: null, // 记录feature的change事件对象
  areaOverlayElement: null, // 记录区域overlayer提示框
  raster: null, // 底图图层
  drawVectorLayer: null,  // 用于展示绘制的矢量图形
  drawFeatureCollection: new Collection(),  // 存放绘制的矢量要素
  pointVectorLayer: null, // 用于展示坐标点
  map: null, // 地图实例引用
  draw: null, // draw实例用于绘制矢量图形
  forbidDraw: false,  // 是否禁止绘制图形
  sliderBtnDragging: false, // 滑块按钮是否正在被拖动
  sliderBtnDragStartPosition: 0, // 记录滑块按钮开始被拖动时的位置
  sliderBtnDragFeature: null, // sliderBtn当前操作的要素
  async init() {
    // 初始化一个底图图层
    this.initBaseMapLayer()
    // 初始化一个矢量数据源, 用于展示绘制的矢量图形
    this.initDrawVectorLayer()
    // 创建一个矢量数据源, 用于展示坐标点
    await this.initPointVectorLayer()
    // 初始化map实例
    this.initMap()
    // 初始化map事件
    this.initMapEvent()
    // 设置操作栏
    this.setActionBar()
    // 设置操作事件
    this.setOperationBtns()
  },
  initBaseMapLayer() {
    this.raster = new TileLayer( {
      source: new OSM()
    })
  },
  initDrawVectorLayer() {
    // 创建一个样式集合
    const style = new Style({
      fill: new Fill({
        color: 'rgba(255, 255, 255, 0.2)'
      }),
      stroke: new Stroke({
        color: '#33cc33',
        width: 2
      }),
      image: new CircleStyle({
        radius: 7,
        fill: new Fill({
          color: '#ffcc33'
        })
      })
    })
    // 创建一个矢量数据源, 用于存放绘制的矢量图形
    const source = new VectorSource({
      features: this.drawFeatureCollection,
      wrapX: false
    })
    // 创建一个矢量图层
    this.drawVectorLayer = new VectorLayer({
      source: source,
      style: style
    })
  },
  async initPointVectorLayer() {
    // 获取所有坐标点
    let result = []
    try {
      // const resData = await getAllPoint({});
      // result = resData.result || []
      result = resResult
      
    } catch (error) {
      console.log(error)
    }
    // 创建一个矢量数据源, 用于存放坐标点
    const pointSource = new VectorSource({
      features: result.map(item => {
        const feature = new Feature({
          geometry: new Point([item.longitude, item.latitude]),
          id: item.identityId
        })
        feature.setStyle((resolution) => {
          return [
            new Style({
              image: new Icon({
                anchor: [0.5, 16],
                anchorXUnits: 'fraction',
                anchorYUnits: 'pixels',
                src: locatePng,
              }),
              text: new Text({
                text: String(item.identityId),
                fill: new Fill({
                  color: 'rgba(216, 30, 6, 1)'
                }),
                font: 'normal 16px 微软雅黑',
              })
            })
          ]
        })
        return feature
      })
    })
    this.pointVectorLayer = new VectorLayer({
      source: pointSource
    })
  },
  initMap() {
    this.map = new Map({
      target: 'map',
      layers: [this.raster, this.pointVectorLayer, this.drawVectorLayer],
      view: new View({
        center: [121.5452456474304, 29.87544350296635],
        zoom: 5,
        projection: 'EPSG:4326'
      })
    })
  },
  initMapEvent() {
    this.map.on('pointermove', (evt) => {
      this.forbidDraw = this.map.hasFeatureAtPixel(evt.pixel, {
        layerFilter: (vectorLayer) => {
          return this.drawVectorLayer.ol_uid === vectorLayer.ol_uid
        }
      })
      this.map.getTargetElement().style.cursor = this.forbidDraw ? 'not-allowed' : ''
    })
  },
  // 清空坐标点图层的所有的要素
  clearPointVectorLayerFeatures(fast) {
    this.pointVectorLayer.getSource().clear({
      fast: fast  // 跳过removefeature事件的调度
    })
  },
  // 添加点要素到坐标点图层上
  addPointVectorLayerFeatures(features) {
    this.pointVectorLayer.getSource().addFeatures(features)
  },
  // 添加交互
  addInteractions(drawType) {
    this.draw = new Draw({
      source: this.drawVectorLayer.getSource(),
      type: this.getGeometryType(drawType),
      geometryFunction: this.getGeometryFunction(drawType)
    })
    this.addCircleEvent(this.draw)
    this.map.addInteraction(this.draw)
  },
  // 删除交互
  removeInteraction() {
    this.map.removeInteraction(this.draw);
    // 删除空的overlayElement元素
    if (this.areaOverlayElement) {
      this.areaOverlayElement.parentNode.removeChild(this.areaOverlayElement);
    }
    // 解绑事件
    if(this.featureChangeListener && !isEmpty(this.featureChangeListener)) {
      unByKey(this.featureChangeListener)
    }
  },
  // 给Draw绑定事件; 添加圆形交互事件
  addCircleEvent(drawInteraction) {
    drawInteraction.on('drawstart', (event) => {
      // 如果点在其他矢量图像上时取消绘制
      if(this.forbidDraw) {
        this.draw.abortDrawing()
        return
      }
      event.feature.set('areaOverlay', this.createAreaOverlayElement())
      const circle = event.feature.getGeometry()
      // 给area overlay添加字标签元素
      this.createAreaOverlayElementInnerHTML(event.feature)
      this.featureChangeListener = circle.on('change', (evt) => {
        this.updateCircleFeatureOverlay(event.feature)
      });
    })
    drawInteraction.on('drawend', (event) => {
      // 重置areaOverlayElement
      this.areaOverlayElement = null
      // 注销feature的change事件
      unByKey(this.featureChangeListener);
    })
  },
  // 创建overlay的内部标签
  createAreaOverlayElementInnerHTML(feature) {
    // 创建删除按钮
    const deleteBtn = this.createDeleteBtn(feature)
    // 创建滑块按钮
    const sliderBtn = this.createSliderBtn(feature)
    const output = `
      <div class="area-info">
        <div class="area-name">区域名字</div>
        <div class="ranging-label">
          <span>0m</span>
        </div>
      </div>
    `
    this.areaOverlayElement.innerHTML = output
    const rangingLabel = $(this.areaOverlayElement).find(".ranging-label")[0];
    $(this.areaOverlayElement).prepend(sliderBtn)
    rangingLabel.appendChild(deleteBtn)
  },
  // 创建要素的overlayer页面元素
  createAreaOverlayElement() {
    // 删除空的overlayElement元素
    if (this.areaOverlayElement) {
      this.areaOverlayElement.parentNode.removeChild(this.areaOverlayElement);
    }
    this.areaOverlayElement = document.createElement('div')
    this.areaOverlayElement.className = 'area-overlay'
    const areaOverlay = new Overlay({
      element: this.areaOverlayElement,
      offset: [0, -10],
      // stopEvent: false,
      positioning: 'bottom-left',
    })
    this.map.addOverlay(areaOverlay)
    return areaOverlay
  },
  // 创建要素的删除按钮
  createDeleteBtn(feature) {
    const deleteBtn = document.createElement('i')
    deleteBtn.className = 'delete-icon iconfont icon-08shanchu'
    deleteBtn.onclick = (e) => {
      e.stopPropagation()
      const geometry = feature.getGeometry()
      const geometryExtent = geometry.getExtent()
      const featuresInExtent = this.pointVectorLayer.getSource().getFeaturesInExtent(geometryExtent)
      featuresInExtent.forEach(feature => {
        feature.setStyle(new Style({
          image: new Icon({
            anchor: [0.5, 16],
            anchorXUnits: 'fraction',
            anchorYUnits: 'pixels',
            src: locatePng
          })
        }))
      })
      this.drawVectorLayer.getSource().removeFeature(feature)
      this.map.removeOverlay(feature.get('areaOverlay'))
    }
    return deleteBtn
  },
  // 创建滑块按钮, 左右移动时更新要素的半径和overlayer的位置
  createSliderBtn(feature) {
    const sliderBtn = document.createElement('div')
    sliderBtn.className = 'slider-btn'
    sliderBtn.innerHTML = `
      <i class="iconfont icon-arrow-left-bold"></i>
      <i class="iconfont icon-arrow-right-bold"></i>
    `
    sliderBtn.onmousedown = (event) => {
      this.sliderBtnDragFeature = feature
      this.onSliderBtnDown(event)
    }
    sliderBtn.ontouchstart = (event) => {
      this.onSliderBtnDown(event)
      this.sliderBtnDragFeature = feature
    }
    return sliderBtn
  },
  // 更新圆feature的半径和overlay
  updateCircleFeatureOverlay(feature, diffRadius = 0) {
    let isOverlap = true
    // 只有半径变大时才有可能和其他的矢量圆相交
    if(diffRadius < 0) {
      isOverlap = false
    } else {
      isOverlap = this.drawFeatureIsOverlap(feature)
    }
    const geom = feature.getGeometry()
    const centerLogLat = geom.getCenter()
    let radius = geom.getRadius()
    radius = radius + diffRadius
    if(this.forbidDraw || isOverlap) {
      let maxRadius = geom.get('maxRadius')
      if(!maxRadius) {
        geom.set('maxRadius', radius, true)
      }
      if(radius > maxRadius) {
        geom.setRadius(maxRadius)
      }
      return
    }
    // 是否不触发feature的change事件更新feature的半径
    if(diffRadius) {
      geom.setRadius(radius)
    } else {
      geom.set('radius', radius, true)
    }
    const meterRadius = getMeterRadius(this.map, radius)
    const areaOverlay = feature.get('areaOverlay')
    const areaOverlayElement = areaOverlay.getElement()
    const rangingLabel = $(areaOverlayElement).find(".ranging-label")
    rangingLabel.children(":first").text(formatLength(meterRadius))
    areaOverlay.setPosition([centerLogLat[0] + radius, centerLogLat[1]])
  },
  // 当鼠标按下时
  onSliderBtnDown(event) {
    event.preventDefault()
    this.onSliderBtnDragStart(event)
    window.addEventListener('mousemove', this.onSliderBtnDragging.bind(this));
    window.addEventListener('touchmove', this.onSliderBtnDragging.bind(this));
    window.addEventListener('mouseup', this.onSliderBtnDragEnd.bind(this));
    window.addEventListener('touchend', this.onSliderBtnDragEnd.bind(this));
    window.addEventListener('contextmenu', this.onSliderBtnDragEnd.bind(this));
  },
  // 当鼠标准备拖动时
  onSliderBtnDragStart(event) {
    this.sliderBtnDragging = true
    if (event.type === 'touchstart') {
      event.clientY = event.touches[0].clientY;
      event.clientX = event.touches[0].clientX;
    }
    this.sliderBtnDragStartPosition = event.clientX;
  },
  // 鼠标移动事件
  onSliderBtnDragging(event) {
    if(!this.sliderBtnDragging) {
      return
    }
    let diff = 0
    if (event.type === 'touchmove') {
      event.clientY = event.touches[0].clientY;
      event.clientX = event.touches[0].clientX;
    }
    diff = event.clientX - this.sliderBtnDragStartPosition
    this.sliderBtnDragStartPosition = event.clientX
    // 设置feature的半径和overlay的位置
    const diffRadius = this.map.getView().getResolution() * diff
    this.updateCircleFeatureOverlay(this.sliderBtnDragFeature, diffRadius)
  },
  // 鼠标移动事件结束
  onSliderBtnDragEnd() {
    if(!this.sliderBtnDragging) {
      return
    }
    window.removeEventListener('mousemove', this.onSliderBtnDragging);
    window.removeEventListener('touchmove', this.onSliderBtnDragging);
    window.removeEventListener('mouseup', this.onSliderBtnDragEnd);
    window.removeEventListener('touchend', this.onSliderBtnDragEnd);
    window.removeEventListener('contextmenu', this.onSliderBtnDragEnd);
    this.sliderBtnDragFeature = null
    this.sliderBtnDragging = false
  },
  // 获取绘制类型
  getGeometryType(drawType) {
    if(drawType === 'Box') {
      return 'Circle'
    }
    return drawType
  },
  // 绘制几何图形
  getGeometryFunction(drawType) {
    let geometryFunction = null
    if(drawType === 'Box') {
      geometryFunction = createBox()
    }
    return geometryFunction
  },
  // 设置交互按钮
  setActionBar() {
    $('.operate > .operate-item').each((index, el) => {
      // 创建tooltip
      new Tooltip(el)
      // 给操作栏添加交互事件
      const $el = $(el)
      $el.on('click', {drawType: $el.data('drawType')}, (event) => {
        // 删除同级元素的active类
        $el.siblings().removeClass('active')
        // 清空交互
        this.removeInteraction()
        // 切换icon是否选中状态
        if($el.hasClass('active')) {
          $el.removeClass('active')
        } else {
          $el.addClass('active')
          this.addInteractions(event.data.drawType)
        }
      })
    })
  },
  // 设置操作按钮
  setOperationBtns() {
    $('#mixed').on('click', () => {
      // 求交集
      // const featureArrays = []
      const featureArray = this.drawFeatureCollection.getArray()
      if(featureArray.length !== 2) {
        return
      }
      const primaryFeature = featureArray[0]
      const secondaryFeature = featureArray[1]
      const primaryGeometry = primaryFeature.getGeometry()
      const secondaryGeometry = secondaryFeature.getGeometry()
      const params = {
        relation: 0,
        primaryTimeSpace: {
          coordinates: primaryGeometry.getCenter(),
          radius: getMeterRadius(this.map, primaryGeometry.getRadius()),
          startTime: $('#pStartTime').val().trim(),
          endTime: $('#pEndTime').val().trim()
        },
        secondTimeSpace: {
          coordinates: secondaryGeometry.getCenter(),
          radius: getMeterRadius(this.map, secondaryGeometry.getRadius()),
          startTime: $('#sStartTime').val().trim(),
          endTime: $('#sEndTime').val().trim()
        }
      }
      getIntersectionPoint(params).then(res => {
        /**
         * 1. 清空所有的点,
         * 2. 添加点
         */
        this.clearPointVectorLayerFeatures(true)
        const { result } = res
        const features = result.map(item => {
          const feature = new Feature({
            geometry: new Point([item.longitude, item.latitude]),
            id: item.identityId
          })
          feature.setStyle((resolution) => {
            return [
              new Style({
                image: new Icon({
                  anchor: [0.5, 16],
                  anchorXUnits: 'fraction',
                  anchorYUnits: 'pixels',
                  src: locatePng,
                }),
                text: new Text({
                  text: String(item.identityId),
                  fill: new Fill({
                    color: 'rgba(216, 30, 6, 1)'
                  }),
                  font: 'normal 16px 微软雅黑',
                })
              })
            ]
          })
          return feature
        })
        this.addPointVectorLayerFeatures(features)
      })
      // featureArray.forEach(feature => {
      //   const geometry = feature.getGeometry()
      //   const geometryExtent = geometry.getExtent()
      //   const featuresInExtent = this.pointVectorLayer.getSource().getFeaturesInExtent(geometryExtent)
      //   featureArrays.push(featuresInExtent)
      // })
      // console.log(featureArrays, 'ssssssssssss')
      // const featureArraysResult = intersectionWith(...featureArrays, function(featureA, featureB) {
      //   const featureAProp = featureA.getProperties()
      //   const featureBProp = featureB.getProperties()
      //   return featureAProp.id === featureBProp.id
      // });
      // console.log(featureArraysResult, 'tttttttt')
      // featureArraysResult.forEach(feature => {
      //   feature.setStyle(new Style({
      //     image: new Icon({
      //       anchor: [0.5, 16],
      //       anchorXUnits: 'fraction',
      //       anchorYUnits: 'pixels',
      //       src: locateSelectedPng
      //     })
      //   }))
      // })
    })
    $('#diffset').on('click', () => {
      // 求差集
      // 生成40000万个点交互明显不流畅
      const points = turf.randomPoint(40000, {bbox: [-80, 30, -60, 60]});
      const featurePoints = new GeoJSON().readFeatures(points)
      this.addPointVectorLayerFeatures(featurePoints)
    })
    $('#feature').on('click', function() {
      // 求图层features
      console.log(drawFeatureCollection)
    })
  },
  // 判断 drawVectorLayer 上绘制的矢量图形是否相交
  drawFeatureIsOverlap(feature) {
    const features = this.drawVectorLayer.getSource().getFeatures()
    const len = features.length
    // 由于turf识别的feature不是openlayer的feature 所以需要做个转换
    const units = this.map.getView().getProjection().getUnits()
    const turfFeature = turf.circle(feature.getGeometry().getCenter(), feature.getGeometry().getRadius(), {
      units: units,
      steps: 13
    })
    
    for(let i = 0; i < len; i++) {
      const item = features[i]
      if(item.ol_uid !== feature.ol_uid) {
        const turfFeatureItem = turf.circle(item.getGeometry().getCenter(), item.getGeometry().getRadius(), {
          units: units,
          steps: 15
        })
        const isOverlap = turf.intersect(turfFeature, turfFeatureItem)
        if(isOverlap) {
          return true
        }
      }
    }
    return false
  }
}

main.init()
